package com.ipan.weixin.msg;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.weixin.msg.general.DefineMenusMsg;
import com.ipan.weixin.msg.general.ImageMsg;
import com.ipan.weixin.msg.general.LinkMsg;
import com.ipan.weixin.msg.general.LocationEventMsg;
import com.ipan.weixin.msg.general.LocationMsg;
import com.ipan.weixin.msg.general.MusicMsg;
import com.ipan.weixin.msg.general.NewsMsg;
import com.ipan.weixin.msg.general.SubscribeEventMsg;
import com.ipan.weixin.msg.general.TextMsg;
import com.ipan.weixin.msg.general.VideoMsg;
import com.ipan.weixin.msg.general.VoiceMsg;
import com.ipan.weixin.msg.general.XmlMsg;
import com.ipan.weixin.util.WxXmlUtils;

/**
 * 将接收的XML打包为Msg对象
 * 
 * 只有rootListener的返回值会被返回到客户端，listeners中的监听器不需要返回值；
 * 
 * @author iPan
 * @version 2013-12-27
 */
public class MessageChain {
	/** 辅助监听器不需要返回值 */
	protected List<MessageListener> listeners;
	/** 根监听器必须有返回值 */
	protected MessageListener rootListener;
	protected Logger logger = LoggerFactory.getLogger(getClass());

	public List<MessageListener> getListeners() {
		return listeners;
	}

	public void setListeners(List<MessageListener> listeners) {
		this.listeners = listeners;
	}
	
	public MessageListener getRootListener() {
		return rootListener;
	}

	public void setRootListener(MessageListener rootListener) {
		this.rootListener = rootListener;
	}

	public void addListener(MessageListener listener) {
		check();
		listeners.add(listener);
	}

	public void removeListener(MessageListener listener) {
		if (listeners == null) {
			return;
		}
		listeners.remove(listener);
	}
	
	private XmlMsg execute(String methodName, XmlMsg msg) {
		if (msg == null || StringUtils.isEmpty(methodName)) {
			return null;
		}
		
		XmlMsg result = null;
		// 执行主要的监听器
		if (rootListener != null) {
			try {
				result = (XmlMsg) MethodUtils.invokeExactMethod(rootListener, methodName, new Object[]{msg});
			} catch (Exception e) {
				logger.error("{}回调消息{}.{}出错.", new Object[]{rootListener.getClass().getName(), msg.getClass().getName(), methodName});
			}
		}
		
		// 执行辅助的监听器
		if (listeners != null) {
			for (MessageListener listener : listeners) {
				try {
					MethodUtils.invokeExactMethod(listener, methodName, new Object[]{msg}); // 无返回值
				} catch (Exception e) {
					logger.error("{}回调消息{}.{}出错.", new Object[]{listener.getClass().getName(), msg.getClass().getName(), methodName});
				}
			}
		}
		return result;
	}

	public XmlMsg process(String xml) {
		if (StringUtils.isEmpty(xml)) {
			return null;
		}

		Document doc = WxXmlUtils.read(xml);
		Element root = doc.getRootElement();
		String msgType = root.elementTextTrim(XmlMsg.EL_MSG_TYPE);
		XmlMsg msg = null;
		XmlMsg result = null;

		if (StringUtils.isEmpty(msgType)) {
			return null;

		} else if (XmlMsg.TYPE_TEXT.equals(msgType)) {
			msg = new TextMsg(doc);
			result = execute("onTextMsg", msg);

		} else if (XmlMsg.TYPE_IMAGE.equals(msgType)) {
			msg = new ImageMsg(doc);
			result = execute("onImageMsg", msg);

		} else if (XmlMsg.TYPE_VOICE.equals(msgType)) {
			msg = new VoiceMsg(doc);
			result = execute("onVoiceMsg", msg);

		} else if (XmlMsg.TYPE_VIDEO.equals(msgType)) {
			msg = new VideoMsg(doc);
			result = execute("onVideoMsg", msg);

		} else if (XmlMsg.TYPE_LOCATION.equals(msgType)) {
			msg = new LocationMsg(doc);
			result = execute("onLocationMsg", msg);

		} else if (XmlMsg.TYPE_LINK.equals(msgType)) {
			msg = new LinkMsg(doc);
			result = execute("onLinkMsg", msg);

		} else if (XmlMsg.TYPE_MUSIC.equals(msgType)) {
			msg = new MusicMsg(doc);
			result = execute("onMusicMsg", msg);

		} else if (XmlMsg.TYPE_NEWS.equals(msgType)) {
			msg = new NewsMsg(doc);
			result = execute("onNewsMsg", msg);

		} else if (XmlMsg.TYPE_EVENT.equals(msgType)) { // 事件推送消息
			String event = root.elementTextTrim(XmlMsg.EL_EVENT);
			
			if (XmlMsg.EVENT_SUBSCRIBE.equals(event) || XmlMsg.EVENT_UNSUBSCRIBE.equals(event) || XmlMsg.EVENT_SCAN.equals(event)) {
				msg = new SubscribeEventMsg(doc);
				result = execute("onSubscribeEventMsg", msg);
				
			} else if (XmlMsg.EVENT_LOCATION.equals(event)) {
				msg = new LocationEventMsg(doc);
				result = execute("onLocationEventMsg", msg);
				
			} else if (XmlMsg.EVENT_CLICK.equals(event)) {
				msg = new DefineMenusMsg(doc);
				result = execute("onDefineMenusMsg", msg);
			}
			result = execute("onEventMsg", msg);
		}
		return result;
	}

	private synchronized void check() {
		if (listeners == null) {
			listeners = new ArrayList<MessageListener>();
		}
	}
}
